package com.demon.framework.boot.job;

import com.demon.framework.common.exception.BizException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.quartz.*;

import java.util.Date;

/**
 * 任务调度服务
 *
 * @author Demon-HY
 * @date 2020/7/24 16:44
 */
@Slf4j
public class JobForTaskService {

    private final Scheduler scheduler;

    public JobForTaskService(Scheduler scheduler) {
        this.scheduler = scheduler;
    }

    /**
     * 新添加定时任务
     *
     * @param task 任务
     * @param date 触发时间
     */
    public void addJob(AbstractTask task, Date date) {
        try {
            JobDataMap jobDataMap = new JobDataMap(BeanUtils.describe(task));
            // 任务名，任务组，任务执行类
            JobDetail jobDetail = JobBuilder.newJob(task.getJobClass()).withIdentity(task.getId(), task.getJobGroup()).setJobData(jobDataMap).build();
            // 触发器
            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
            // 触发器名,触发器组
            triggerBuilder.withIdentity(task.getId(), task.getJobGroup());
            // 触发器时间设定
            triggerBuilder.startAt(date);
            // 创建Trigger对象
            Trigger trigger = triggerBuilder.build();
            // 调度容器设置JobDetail和Trigger
            scheduler.scheduleJob(jobDetail, trigger);
            log.info("新增任务成功，task:{}", task);
        } catch (Exception e) {
            log.error("新增任务失败，task:{}", task, e);
            throw new BizException("新增任务失败", e);
        }
    }

    /**
     * 重置定时任务的时间
     *
     * @param task 任务
     * @param date 触发时间
     */
    public void resetJobTime(AbstractTask task, Date date) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(task.getId(), task.getJobGroup());
            if (scheduler.checkExists(triggerKey)) {
                // 触发器
                TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
                // 触发器名,触发器组
                triggerBuilder.withIdentity(task.getId(), task.getJobGroup());
                // 触发器时间设定
                triggerBuilder.startAt(date);
                // 创建Trigger对象
                Trigger trigger = triggerBuilder.build();
                // 方式一 ：修改一个任务的触发时间
                scheduler.rescheduleJob(triggerKey, trigger);
                log.info("重置任务时间成功，task:{},重置到时间:{}", task, date.toString());
            } else {
                log.warn("重置任务时间不存在，task:{},新增定时任务", task);
                addJob(task, date);
            }
        } catch (Exception e) {
            log.error("重置任务时间失败，task:{}", task, e);
        }
    }

    /**
     * 重置定时任务 内的数据
     */
    public void resetJobData(AbstractTask task) {
        JobKey jobKey = new JobKey(task.getId(), task.getJobGroup());
        try {
            if (scheduler.checkExists(jobKey)) {
                JobDataMap jobDataMap = new JobDataMap(BeanUtils.describe(task));
                JobDetail jobDetail = JobBuilder.newJob(task.getJobClass()).withIdentity(jobKey).setJobData(jobDataMap).build();
                scheduler.addJob(jobDetail, true, true);
                log.info("重置任务数据成功，task:{}", task);
            } else {
                log.warn("重置任务数据不存在，task:{}", task);
                throw new BizException("重置任务数据不存在!");
            }

        } catch (Exception e) {
            log.error("重置任务数据失败，task:{}", task, e);
            throw new BizException("重置任务数据失败", e);
        }

    }


    /**
     * 新添加定时任务根据表达式
     */
    public void addJobByCron(AbstractTask task, String cron) {
        try {
            // 任务名，任务组，任务执行类
            JobDetail jobDetail = JobBuilder.newJob(task.getJobClass()).withIdentity(task.getId(), task.getJobGroup()).build();

            // 触发器
            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
            // 触发器名,触发器组
            triggerBuilder.withIdentity(task.getId(), task.getJobGroup());
            // 触发器时间设定
            triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
            // 创建Trigger对象
            Trigger trigger = triggerBuilder.build();
            // 调度容器设置JobDetail和Trigger

            scheduler.scheduleJob(jobDetail, trigger);
            log.info("任务添加成功，task:{}", task);
        } catch (Exception e) {
            log.error("任务添加失败，task:{}", task, e);
            throw new BizException("任务添加失败", e);
        }
    }

    /**
     * 重置定时任务
     */
    public void resetJobByCron(AbstractTask task, String cron) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(task.getId(), task.getJobGroup());
            if (scheduler.checkExists(triggerKey)) {
                // 触发器
                TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
                // 触发器名,触发器组
                triggerBuilder.withIdentity(task.getId(), task.getJobGroup());
                // 触发器时间设定
                triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
                // 创建Trigger对象
                Trigger trigger = triggerBuilder.build();
                scheduler.rescheduleJob(triggerKey, trigger);
            } else {
                addJobByCron(task, cron);
            }
        } catch (Exception e) {
            log.error("任务重置失败，task:{}", task, e);
            throw new BizException("任务重置失败", e);
        }
    }


    /**
     * 删除定时任务
     */
    public void delJob(AbstractTask task) {
        try {
            delJob(task.getId(), task.getJobGroup());
            log.info("任务删除成功，task:{}", task);
        } catch (Exception e) {
            log.error("任务删除失败，task:{}", task, e);
            throw new BizException("任务删除失败", e);
        }
    }

    /**
     * 删除定时任务
     */
    public void delJob(String taskId, String jobGroup) {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(taskId, jobGroup);
            scheduler.pauseTrigger(triggerKey);// 停止触发器
            scheduler.unscheduleJob(triggerKey);// 移除触发器
            /*scheduler.deleteJob(JobKey.jobKey(task.getId(), task.getJobGroup()));*/ //删除任务
            log.info("任务删除成功，taskId:{},jobGroup:{}", taskId, jobGroup);
        } catch (Exception e) {
            log.error("任务删除失败，taskId:{},jobGroup:{}", taskId, jobGroup, e);
            throw new BizException("任务删除失败", e);
        }
    }

}
